#include <iostream>
#include "../includes/need-a-name.hh"
#include "../includes/project-base.hh"
#include "../includes/subproject-base.hh"
#include "../includes/equation-base.hh"
#include "../includes/init-base.hh"
#include "../includes/boundary-base.hh"

#include "../equations/includes/constant-advection.hh"
#include "includes/project_constantAdvection_1D_YASP.hh"
#include "../initcollecter/includes/initcollecter-constant-advection.hh"

namespace conadv{
class LFTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="lfTest";
  }
  void assign_equation(){
    std::cout<<"assign constant-advection equation"<<std::endl;
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::spacediscrete = setting::lf;
    memory::dgflag=0;
    // std::cout<<equation->para["u0"]<<std::endl;
    // equation->set_parameter("u0",2.0);
  }
  void dataanalysis(){
  //   for(int tmpi=0; tmpi<memory::variable.size(); tmpi++)
  //     std::cout<< memory::variable.size() << std::endl;
  }
};

class dgLFTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="dgLFTest";
  }
  void assign_equation(){
    std::cout<<"assign constant-advection equation"<<std::endl;
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::spacediscrete = setting::lf;
    memory::dgflag=1;    
    memory::dgorder=3;
    memory::intergnumber=500;    
  }
  void dataanalysis(){
  }
};

class TVDLFTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="tvdlfTest";
  }
  void assign_equation(){
    equation=new ConstantAdvection();
  }  
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::spacediscrete = setting::tvdlf;
    setting::limiter = setting::minmod;
    memory::dgflag=0;    
    // dataanalysis::auxnumber=4;
    // dataanalysis::auxvariablename.push_back("limitslope");
    // dataanalysis::auxvariablename.push_back("slopeleft");
    // dataanalysis::auxvariablename.push_back("sloperight");
    // dataanalysis::auxvariablename.push_back("slopecenter");

    // dataanalysis::auxvariablename.push_back("slopeleft");
    // dataanalysis::auxvariablename.push_back("sloperight");
    // dataanalysis::auxvariablename.push_back("varleft");
    // dataanalysis::auxvariablename.push_back("varright");        
  }
  void dataanalysis(){
    // for(int tmpi=0; tmpi<memory::variable[0].size(); tmpi++)
    //   memory::variable[memory::phynumber][tmpi]=memory::limit_slope[0][0][tmpi];
  }
};

class dgTVDLFTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="dgTVDLFTest";
  }
  void assign_equation(){
    std::cout<<"assign constant-advection equation"<<std::endl;
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::spacediscrete = setting::tvdlf;
    memory::dgflag=1;
    memory::dgorder=2;
    memory::intergnumber=500;    
  }
  void dataanalysis(){
  }
};
  
class dgrkLFTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="dgrkLFTest";
  }
  void assign_equation(){
    std::cout<<"assign constant-advection equation"<<std::endl;
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::spacediscrete = setting::lf;
    setting::timeadvance=setting::rk3;    
    memory::dgflag=1;
    memory::dgorder=3;    
    memory::intergnumber=500;    
  }
  void dataanalysis(){
  }
};
  
class LWTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="lwTest";
  }
  void assign_equation(){
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::spacediscrete = setting::lw;
  }
  void dataanalysis(){
  }
};

class rk2TVDLFTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="rk2TVDLFTest";
  }
  void assign_equation(){
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    memory::dgflag=0;
    memory::dgorder=0;          
    std::cout<<"set unique parameters"<<std::endl;
    setting::timeadvance=setting::rk2;
    setting::spacediscrete = setting::tvdlf;
    setting::limiter = setting::minmod;    
  }
  void dataanalysis(){
  }
};

class rk3TVDLFTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="rk3TVDLFTest";
  }
  void assign_equation(){
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::timeadvance=setting::rk3;
    setting::spacediscrete = setting::tvdlf;
    setting::limiter = setting::superbee;
    timerule::cfl=0.6;    
  }
  void dataanalysis(){
  }
};

class UpwindTest : public SubprojectBase{
public:
  void set_subproject_signature(){
    subproject_signature="upwindTest";
  }
  void assign_equation(){
    equation=new ConstantAdvection();
  }
  void assign_initialcondition(){
    init=new InitCollecterConstantAdvection();
  }
  void assign_boundarycondition(){
    boundary=new BoundaryBase();
  }
  void set_unique_parameters(){
    std::cout<<"set unique parameters"<<std::endl;
    setting::spacediscrete = setting::upwind;
  }
  void dataanalysis(){}
};

}
//-----------------------------------------
Project_constantAdvection_1D_YASP::Project_constantAdvection_1D_YASP(){ 
}
Project_constantAdvection_1D_YASP::~Project_constantAdvection_1D_YASP(){
}
void Project_constantAdvection_1D_YASP::set_project_signature(){
  project_signature="constantAdvection_1D_YASP";
}
void Project_constantAdvection_1D_YASP::set_common_parameters(int subproj){
  // Grid and dimension need to be assigned in driver-file.cc and setting.hh
  // Grid: #define YASP
  // dimension: const int dimension=1
  setting::timeadvance=setting::euler;
  setting::boundary=setting::constant;
  gridsetting::lower[0]=0.0;
  gridsetting::upper[0]=2.0;
  gridsetting::element[0]=200;
  timerule::start=0.0;
  timerule::end=1.0;
  timerule::dt=1.0E-100;
  timerule::current=0.0;
  timerule::counter=0.0;
  timerule::cfl=0.8;
  memory::dgorder=0;
  memory::dgflag=0;  
  // equation parameter
  // TODO: u0=-1.0, zero_boun, boundary can not work perfectly.
  get_subproject(subproj)->equation->set_parameter("u0",1.0);
  // init parameter
  get_subproject(subproj)->init->set_parameter("cen1",1.0);
  get_subproject(subproj)->init->set_parameter("wid1",0.2);
  get_subproject(subproj)->init->set_parameter("rectangle",1.0);
  get_subproject(subproj)->init->set_parameter("circle",0.0);    
  // boundary setting
  for(int tmpp=0; tmpp<memory::phynumber; tmpp++)
    for(int tmpd=0; tmpd<gridsetting::dimension; tmpd++){
      get_subproject(subproj)->boundary->left[tmpp][tmpd]="const";
      get_subproject(subproj)->boundary->left[tmpp][tmpd]="const";      
    }
}

// double Project_constantAdvection_1D_YASP::recWidth[gridsetting::dimension];
// double Project_constantAdvection_1D_YASP::recCenter[gridsetting::dimension];
// double Project_constantAdvection_1D_YASP::velocity[gridsetting::dimension];

void Project_constantAdvection_1D_YASP::load_subprojects(){
  add_subproject(new conadv::LFTest());
  // add_subproject(new conadv::dgLFTest());
  add_subproject(new conadv::TVDLFTest());  
  // add_subproject(new conadv::dgTVDLFTest());
  add_subproject(new conadv::rk2TVDLFTest());
  // add_subproject(new conadv::dgrkLFTest());    
  add_subproject(new conadv::UpwindTest());
  // // // TODO: crash if put after tdvlf
  add_subproject(new conadv::LWTest());
  add_subproject(new conadv::rk3TVDLFTest());
};
